using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Xml;
using System.Windows.Forms;

namespace OpenMTS
{
    public class ProjectItem
    {
        private string sFileName;

        public string FileName
        {
            get { return sFileName; }
            set { sFileName = value; }
        }
        public ProjectFile.FILE_TYPE FileType;
        public string Path;
    }

    public class ProjectFile
    {
        public enum FILE_TYPE  {schema,directory,ruleset,message,report};
        public enum CHANGE_TYPE { File_Added, File_Deleted };

        private string sName;
        private string location;
        private XmlDocument xProject = null;
       
        public static  string ProjectFileFilter = @"Project files (*.prj)|*.prj|All files (*.*)|*.*";
        public static string ProjectFileExtenstion = @"prj";

        public delegate void ProjectLoad(ProjectFile project);
        public static event ProjectLoad ProjectLoadEvent;

        public delegate void ProjectChanged(ProjectFile project, CHANGE_TYPE type, ProjectItem item);
        public static event ProjectChanged ProjectChangedEvent;

        private ProjectFile() 
        {
                       
        }

        

        public static ProjectFile loadProjectFile(string fileName)
        {
            ProjectFile pf = new ProjectFile();
            pf.xProject = new XmlDocument();
            pf.xProject.Load(fileName);

            int i = fileName.LastIndexOf('\\');
            if (i == -1)
                throw new Exception(string.Format("Can not get directory from file name: {0}", fileName));

            pf.Location = fileName.Substring(0,i);

            XmlNode xRoot = pf.ProjectRoot; 
            pf.Name = xRoot.Attributes["name"].Value;

            ProjectLoadEvent(pf);
            return pf;

        }

        private string getFileNameFromPath(string fullPath)
        {
            int i = fullPath.LastIndexOf('\\');
            if (i != -1)
                return fullPath.Substring(i + 1);

            return fullPath;

        }

        public static ProjectFile createProjectFile(string name, string location)
        {
            ProjectFile pf = new ProjectFile();
            pf.Location = location;

        
            System.IO.DirectoryInfo di = new DirectoryInfo(pf.location);
            if (!di.Exists)
            {
                di.Create();
            }
            
            FileInfo[] projFiles = di.GetFiles(string.Format("*.{0}",
                    ProjectFile.ProjectFileExtenstion));
            if (projFiles.Length > 0)
               throw new Exception("A Project file already exists in this directory.");

            pf.xProject = new XmlDocument();
            XmlNode root = pf.xProject.CreateNode(XmlNodeType.Element, "Project", null);
            XmlAttribute aProject = pf.xProject.CreateAttribute("name");
           
            aProject.Value = pf.sName = name;
            root.Attributes.Append(aProject);
            pf.xProject.AppendChild(root);

            di.CreateSubdirectory("schemas");
            root.AppendChild(pf.createFileNode("schemas", FILE_TYPE.directory));
            di.CreateSubdirectory("rulesets");
            root.AppendChild(pf.createFileNode("rulesets", FILE_TYPE.directory));
             
            pf.Save();

            ProjectLoadEvent(pf);

            return pf;
        }

        public void Save()
        {
            
            this.xProject.Save(string.Format("{0}{1}.{2}",
                this.Location, this.Name, ProjectFile.ProjectFileExtenstion));
        }

        
        private XmlNode createFileNode(string name, FILE_TYPE type)
        {
            XmlNode fileNode = xProject.CreateNode(XmlNodeType.Element, "File", null);
            XmlAttribute attrName = xProject.CreateAttribute("name");
            attrName.Value = name;
            fileNode.Attributes.Append(attrName);
            XmlAttribute attrType = xProject.CreateAttribute("type");
            attrType.Value = type.ToString();
            fileNode.Attributes.Append(attrType);

            return fileNode;
        }


        public XmlNode ProjectRoot
        {
            get { return xProject.SelectSingleNode(@"//Project"); }
        }

        /// <summary>
        /// A string value representing the Name of the project. Basically the filename minus extension
        /// </summary>
        public string Name
        {
            get { return sName; }
            set { sName = value; }
            
        }

        /// <summary>
        /// A string value of the directory the Project file exists in when it was created\loaded.
        /// This value is not saved since the Project can be moved.
        /// Format is c:\whatever\
        /// </summary>
        public string Location
        {
            get { return location; }
            set
            {
                if (!value.EndsWith("\\"))
                    value += "\\";
                location = value;
            }
        }

        public string SchemaLocation
        {
            get { return Location + "schemas\\"; }
        }

        public XmlNode addFile(string fullPathName, FILE_TYPE fileType)
        {
            XmlNode rc = null;
            switch (fileType)
            {
                case FILE_TYPE.schema:
                    {
                        XmlNode n = ProjectRoot.SelectSingleNode(@"./File[@name='schemas']");
                        if (n != null)
                        {
                            string fileName = getFileNameFromPath(fullPathName);
                            //copy file
                            File.Copy(fullPathName,
                                string.Format("{0}schemas\\{1}", Location, fileName));
                            rc = this.createFileNode(fileName, FILE_TYPE.schema);
                            n.AppendChild(rc);
                            ProjectItem pi = new ProjectItem();
                            pi.FileName = fileName;
                            pi.FileType = FILE_TYPE.schema;
                            pi.Path = Location; //TODO: append rulesets dir
                            ProjectChangedEvent(this, CHANGE_TYPE.File_Added, pi);
                            
                        }
                    }
                    break;
                case FILE_TYPE.ruleset:
                    {
                        XmlNode n = ProjectRoot.SelectSingleNode(@"./File[@name='rulesets']");
                        if (n != null)
                        {
                            string fileName = getFileNameFromPath(fullPathName);
                            //copy file
                            File.Copy(fullPathName,
                                string.Format("{0}rulesets\\{1}", Location, fileName));
                            rc = this.createFileNode(fileName, FILE_TYPE.ruleset);
                            n.AppendChild(rc);
                            ProjectItem pi = new ProjectItem();
                            pi.FileName = fileName;
                            pi.FileType = FILE_TYPE.ruleset;
                            pi.Path = Location; //TODO: append rulesets dir
                            ProjectChangedEvent(this, CHANGE_TYPE.File_Added, pi);
                            
                        }
                    }
                    break;
                case FILE_TYPE.message:
                    {
                       
                            string fileName = getFileNameFromPath(fullPathName);
                            //copy file
                            File.Copy(fullPathName,
                                string.Format("{0}{1}", Location, fileName));
                            rc = this.createFileNode(fileName, FILE_TYPE.message);
                            ProjectRoot.AppendChild(rc);
                            ProjectItem pi = new ProjectItem();
                            pi.FileName = fileName;
                            pi.FileType = FILE_TYPE.message;
                            pi.Path = Location;
                            ProjectChangedEvent(this, CHANGE_TYPE.File_Added, pi);
                        
                    }
                    break;
            }

            Save();
            return rc;
        }

        public ProjectItem[] getMessageFileList()
        {
            ProjectItem[] messages = null;
            if (this.ProjectRoot != null)
            {
                XmlNodeList msgNodes = this.ProjectRoot.SelectNodes(@"//File[@type='message']");
                messages = new ProjectItem[msgNodes.Count];
                int i = 0;
                foreach (XmlNode node in msgNodes)
                {
                    messages[i] = new ProjectItem();
                    messages[i].FileName = node.Attributes["name"].Value;
                    messages[i].Path = Location;
                    messages[i].FileType = FILE_TYPE.message;
                    i++;
                }

            }

            return messages;
        }

        public ProjectItem[] getRulesetFileList()
        {
            ProjectItem[] messages = null;
            if (this.ProjectRoot != null)
            {
                XmlNodeList msgNodes = this.ProjectRoot.SelectNodes(@"//File[@type='ruleset']");
                messages = new ProjectItem[msgNodes.Count];
                int i = 0;
                foreach (XmlNode node in msgNodes)
                {
                    messages[i] = new ProjectItem();
                    messages[i].FileName = node.Attributes["name"].Value;
                    messages[i].Path = Location + "rulesets\\";
                    messages[i].FileType = FILE_TYPE.ruleset;
                    i++;
                }

            }

            return messages;
        }
        
    }
}
